#!/usr/bin/env python
"""
Wrapper for ocaml based FSA package.
"""

import os
import re
from pyrna.utils import which

###############################################################################

OCAML_FSA_PATH = which('fsa')

###############################################################################

def make_pt2(f_motifs):
    """
    fsa make_pt2 file, outputs a prefix tree for the words in file
    """
    assert os.path.exists(f_motifs)
    
    outfile = f_motifs + ".ptr"
    if not os.path.exists(outfile):
        os.system(OCAML_FSA_PATH + " make_pt2 " + f_motifs + " > " + outfile)

    return outfile

###############################################################################
    
def determinize(infile):
    """
    determinize and minimize
    """
    outfile = infile + ".det"
    if not os.path.exists(outfile):
        os.system(OCAML_FSA_PATH + " determinize -rn " + infile 
                  + " > " + outfile)

    return outfile

###############################################################################
    
def minimize(infile):
    """
    fsa minimize file, outputs an FSA isomorphic to 
    the canonical acceptor for the FSA in file.
    """
    outfile = infile + ".m"
    if not os.path.exists(outfile):
        os.system(OCAML_FSA_PATH + " minimize -rn " + infile + " > " + outfile)

    return outfile

###############################################################################
    
def complement(infile, outfile=None):
    """
    fsa complement file, outputs the complement of the FSA in file.
    rename, minimize, then rename.
    """
    if not outfile:
        outfile = infile + ".cmpl"
    if not os.path.exists(outfile):
        os.system(OCAML_FSA_PATH + " complement -rn -m -rn " + infile + " > " 
                  + outfile)

    return outfile

###############################################################################

def plotFsa(fsafile, format):
    """
    Plot a FSA to a file in format given
    """
    
    dotfile = fsafile + ".dot"
    figfile = fsafile + "." + format
    if not os.path.exists(dotfile):
        os.system(OCAML_FSA_PATH + " to_dot " + fsafile + " > " + dotfile)

    if not os.path.exists(figfile):
        os.system("dot -Grankdir=TD -T" + format + " " + dotfile + " -o " 
                  + figfile)

    return figfile

###############################################################################

def generate(fsafile, n, m, outfile=None):
    """
    fsa generate N M file
    outputs all words between sizes N and M accepted by the FSA in fsafile
    """
    if not outfile:
        outfile = fsafile + "_" + str(n) + "-" + str(m) + ".seq"
    if not os.path.exists(outfile):
        os.system(OCAML_FSA_PATH + " generate " + str(n) + " " + str(m) + " " 
                  + fsafile + " > " + outfile)
    
    return outfile

###############################################################################

def inter(f1, f2, outfile=None):
    """
    fsa inter file1 file2 
    outputs the intersection of the FSAs in file1 and file2.
    """
    assert os.path.exists(f1)
    assert os.path.exists(f2)

    if not outfile:
        outfile = f1 + '_inter_' + f2
    if not os.path.exists(outfile):
        os.system(OCAML_FSA_PATH + " inter -rn -m -rn " + f1 + " " + f2 + 
                  " > " + outfile)

    return outfile
    
###############################################################################

def report(f_fsa, outfile=None):
    """
    fsa report file
    outputs to standard output the number of start states, final states,
    and the total number of states and transitions of the fsa in file.
    """
    assert os.path.exists(f_fsa)
    
    if not outfile:
        outfile = f_fsa + '.report'
    if not os.path.exists(outfile):
        os.system(OCAML_FSA_PATH + " report " + f_fsa + " > " + outfile)

    lines = [line.rstrip() for line in open(outfile).readlines()]

    pat = re.compile('(\d+)')
    
    num_start = int(pat.search(lines[0]).group(1))
    num_final = int(pat.search(lines[1]).group(1))
    um_states = int(pat.search(lines[2]).group(1))
    num_trans = int(pat.search(lines[3]).group(1))

    return num_start,num_final,um_states,num_trans

###############################################################################
